home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
PROGRAM
/
INDENT3.ARJ
/
INDENT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-08-04
|
15KB
|
509 lines
/* Copyright (c) 1980 Regents of the University of California. All rights
* reserved. The Berkeley software License Agreement specifies the terms and
* conditions for redistribution. */
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1980 Regents of the University of California.\n\
All rights reserved.\n";
#endif not lint
#ifndef lint
static char sccsid[] = "@(#)indent.c 5.4 (Berkeley) 9/10/85";
#endif not lint
/*-
Copyright (C) 1976
by the
Board of Trustees
of the
University of Illinois
All rights reserved
NAME:
indent main program
FUNCTION:
This is the main program of the indent program. Indent will take a C
program source and reformat it into a semi-reasonable form.
ALGORITHM:
The routine lexi scans tokens and passes them back one at a time to the
main routine. The subroutine parse takes care of much of the work of
figuring indentation level.
1) Call lexi
2) Enter a monster switch statement on the code returned by lexi. If
the indentation level for the line yet to be printed should be
changed, set the variable ps.ind_level. If the indentation level for
the following line should be changed, set the variable ps.i_l_follow.
*/
#include "indent_globs.h"
char *in_name = "<stdin>"; /* will always point to name of input file */
char *out_name = "<stdout>"; /* will always point to name of output file */
char bakfile[32] = "";
int dec_ind; /* current indentation for declarations */
int di_stack[STACKS]; /* a stack of structure indentation levels */
int flushed_nl; /* used when buffering up comments to
* remember that a newline was passed over */
int force_nl; /* when true, code must be broken */
int hd_type; /* used to store type of stmt for if (...),
* for (...), etc */
int scase; /* set to true when we see a case, so we will
* know what to do with the following colon */
int sp_sw; /* when true, we are in the expressin of
* if(...), while(...), etc. */
int squest; /* when this is positive, we have seen a ?
* without the matching : in a <c>?<s>:<s>
* construct */
int type_code; /* the type of token, returned by lexi */
int last_else = 0; /* true iff last keyword was an else */
int is_procname;
#ifdef BUFFERING
char *inbuf, *outbuf; /* buffering buffers */
#endif
void main(argc, argv)
int argc;
char **argv;
{
register char *t_ptr; /* used for copying tokens */
register int i;
/*-----------------------------------------------*\
| INITIALIZATION |
\*-----------------------------------------------*/
sp_sw = force_nl = false;
dec_ind = 0;
squest = 0;
di_stack[ps.dec_nest = 0] = 0;
scase = ps.pcase = false;
ps.p_stack[0] = stmt; /* this is the parser's stack */
ps.last_nl = true; /* this is true if the last thing scanned was
* a newline */
ps.last_token = semicolon;
combuf[0] = codebuf[0] = labbuf[0] = ' '; /* set up code, label, and
* comment buffers */
combuf[1] = codebuf[1] = labbuf[1] = '\0';
s_lab = e_lab = labbuf + 1;
s_code = e_code = codebuf + 1;
s_com = e_com = combuf + 1;
buf_ptr = buf_end = in_buffer;
line_no = 1;
had_eof = ps.in_decl = ps.decl_on_line = break_comma = false;
ps.in_or_st = false;
ps.bl_line = true;
ps.want_blank = ps.in_stmt = ps.ind_stmt = false;
sc_end = 0;
bp_save = 0;
be_save = 0;
output = NULL;
/*--------------------------------------------------*\
| COMMAND LINE SCAN
\*--------------------------------------------------*/
set_defaults();
/* Unfortunately, we must look for -npro here because the profiles are
* read before the command line arguments. */
for (i = 1; i < argc; ++i)
if (strcmp(argv[i], "-npro") == 0)
break;
if (i >= argc)
set_profile();
input = NULL; /* cancel -st if it was in the profiles, */
output = NULL; /* as it doesn't make any sense there. */
for (i = 1; i < argc; ++i) {
/* look thru args (if any) for changes to defaults */
if (argv[i][0] != '-') {/* no flag on parameter */
if (input == NULL) {/* we must have the input file */
in_name = argv[i]; /* remember name of input file */
input = fopen(in_name, "r");
if (input == NULL) { /* check for open error */
fprintf(stderr, "indent: can't open %s\n", argv[i]);
exit(1);
}
continue;
} else if (output == NULL) { /* we have the output file */
out_name = argv[i]; /* remember name of output file */
if (strcmp(in_name, out_name) == 0) { /* attempt to overwrite
* the file */
fprintf(stderr, "indent: input and output files must be different\n");
exit(1);
}
output = fopen(out_name, "w");
if (output == NULL) { /* check for create error */
fprintf(stderr, "indent: can't create %s\n", argv[i]);
exit(1);
}
continue;
}
fprintf(stderr, "indent: unknown parameter: %s\n", argv[i]);
exit(1);
} else
set_option(argv[i]);
} /* end of for */
if (input == NULL) {
fprintf(stderr, "Usage: indent file [ outfile ] [ options ]\n");
exit(1);
}
if (output == NULL) {
if (troff)
output = stdout;
else {
out_name = in_name;
bakcopy();
}
}
#ifdef BUFFERING
if ((inbuf = malloc(BUFSIZ)) == NULL || (outbuf = malloc(BUFSIZ)) == NULL) {
fprintf(stderr, "indent: out of memory!\n");
exit(1);
}
if (setvbuf(input, inbuf, _IOFBF, BUFSIZ) || setvbuf(output, outbuf, _IOFBF, BUFSIZ)) {
fprintf(stderr, "indent: bufferring error!\n");
exit(1);
}
#endif
/* Adjust parameters that are out of range, or set defaults if no values
* were specified. */
if (ps.com_ind <= 1)
ps.com_ind = 2; /* dont put normal comments before column 2 */
if (block_comment_max_col <= 0)
block_comment_max_col = max_col;
if (ps.decl_com_ind <= 0) /* if not specified by user, set this */
ps.decl_com_ind = ps.ljust_decl ? ps.com_ind - 8 : ps.com_ind;
if (ps.decl_com_ind <= 1)
ps.decl_com_ind = 2;
if (continuation_indent == 0)
continuation_indent = ps.ind_size;
fill_buffer(); /* get first batch of stuff into input buffer */
parse(semicolon);
dosomething();
if (troff) { /* this isn't going to work, but since there
* isn't much call for troff on the PC, I
* don't care. I'll leave it here though, for
* your sake. */
register char *p = in_name, *beg = in_name;
while (*p)
if (*p++ == '/')
beg = p;
fprintf(output, ".Fn \"%s\"\n", beg);
}
/*------------------------------*\
| START OF MAIN LOOP |
\*------------------------------*/
for (;;) { /* this is the main loop. it will go until
* we reach eof */
type_code = lexi(); /* lexi reads one token. The actual
* characters read are stored in "token".
* lexi returns a code indicating the type of
* token */
is_procname = ps.procname[0];
/* The following code moves everything following an if (), while (),
* else, etc. up to the start of the following stmt to a buffer. This
* allows proper handling of both kinds of brace placement. */
flushed_nl = false;
while (ps.search_brace) { /* if we scanned an if(), while(),
* etc., we might need to copy stuff
* into a buffer we must loop,
* copying stuff into save_com, until
* we find the start of the stmt
* which follows the if, or whatever */
switch (type_code) {
case newline:
++line_no;
flushed_nl = true;
case form_feed:
break; /* form feeds and newlines found here will be
* ignored */
case lbrace: /* this is a brace that starts the compound
* stmt */
if (sc_end == 0) { /* ignore buffering if a comment
* wasn't stored up */
ps.search_brace = false;
goto check_type;
}
if (btype_2) {
save_com[0] = '{'; /* we either want to put the
* brace right after the if */
goto sw_buffer; /* go to common code to get
* out of this loop */
}
case comment: /* we have a comment, so we must copy it into
* the buffer */
if (!flushed_nl) {
if (sc_end == NULL) { /* if this is the first
* comment, we must set up
* the buffer */
save_com[0] = save_com[1] = ' ';
sc_end = &(save_com[2]);
} else {
*sc_end++ = '\n'; /* add newline between
* comments */
*sc_end++ = ' ';
--line_no;
}
*sc_end++ = '/'; /* copy in start of comment */
*sc_end++ = '*';
for (;;) { /* loop until we get to the end of
* the comment */
*sc_end = *buf_ptr++;
if (buf_ptr >= buf_end)
fill_buffer();
if (*sc_end++ == '*' && *buf_ptr == '/')
break; /* we are at end of comment */
if (sc_end >= &(save_com[sc_size])) { /* check for temp buffer
* overflow */
diag(1, "Internal buff overflow - Move too large comment after if, while.");
cleanup(1);
}
}
*sc_end++ = '/'; /* add ending slash */
if (++buf_ptr >= buf_end) /* get past / in buffer */
fill_buffer();
break;
}
default: /* it is the start of a normal statment */
if (flushed_nl) /* if we flushed a newline, make sure
* it is put back */
force_nl = true;
if (type_code == sp_paren && *token == 'i'
&& last_else && ps.else_if
|| type_code == sp_nparen && *token == 'e'
&& e_code != s_code && e_code[-1] == '}')
force_nl = false;
if (sc_end == NULL) { /* ignore buffering if
* comment wasnt saved up */
ps.search_brace = false;
goto check_type;
}
if (force_nl) { /* if we should insert a nl here, put
* it into the buffer */
force_nl = false;
--line_no; /* this will be re-increased when the
* nl is read from the buffer */
*sc_end++ = '\n';
*sc_end++ = ' ';
if (verbose && !flushed_nl) /* print error msg if
* the line was not
* already broken */
diag(0, "Line broken");
flushed_nl = false;
}
for (t_ptr = token; *t_ptr; ++t_ptr)
*sc_end++ = *t_ptr; /* copy token into temp
* buffer */
sw_buffer:
ps.search_brace = false; /* stop looking for start of
* stmt */
bp_save = buf_ptr; /* save current input buffer */
be_save = buf_end;
buf_ptr = save_com; /* fix so that subsequent
* calls to lexi will take
* tokens out of save_com */
*sc_end++ = ' '; /* add trailing blank, just in case */
buf_end = sc_end;
sc_end = 0;
break;
} /* end of switch */
if (type_code != 0) /* we must make this check, just in case
* there was an unexpected EOF */
type_code = lexi(); /* read another token */
is_procname = ps.procname[0];
} /* end of while (ps.search_brace) */
last_else = 0;
check_type:
if (type_code == 0) { /* we got eof */
if (s_lab != e_lab || s_code != e_code
|| s_com != e_com) /* must dump end of line */
dump_line();
if (ps.tos > 1) /* check for balanced braces */
diag(1, "Stuff missing from end of file.");
if (verbose) {
printf("There were %d output lines and %d comments\n",
ps.out_lines, ps.out_coms);
printf("(Lines with comments)/(Lines with code): %6.3f\n",
(1.0 * ps.com_lines) / code_lines);
}
cleanup(ps.tos <= 1);
}
if (
(type_code != comment) &&
(type_code != newline) &&
(type_code != preesc) &&
(type_code != form_feed)) {
if (force_nl && (type_code != semicolon) && (type_code != lbrace || !btype_2)) { /* we should force a
* broken line here */
if (verbose && !flushed_nl)
diag(0, "Line broken");
flushed_nl = false;
dump_line();
ps.want_blank = false; /* dont insert blank at line start */
force_nl = false;
}
ps.in_stmt = true; /* turn on flag which causes an extra level
* of indentation. this is turned off by a ;
* or '}' */
if (s_com != e_com) { /* the turkey has embedded a comment
* in a line. fix it */
*e_code++ = ' ';
for (t_ptr = s_com; *t_ptr; ++t_ptr)
*e_code++ = *t_ptr;
*e_code++ = ' ';
*e_code = '\0'; /* null terminate code sect */
ps.want_blank = false;
e_com = s_com;
}
} else if (type_code != comment) /* preserve force_nl thru a
* comment */
force_nl = false;
/* cancel forced newline after newline, form feed, etc */
switch_on(type_code);
*e_code = '\0'; /* make sure code section is null terminated */
if (type_code != comment && type_code != newline && type_code != preesc)
ps.last_token = type_code;
} /* end of main for(;;) loop */
}
void dosomething()
{
register char *p = buf_ptr;
register col = 1;
for (;;) {
if (*p == ' ')
col++;
else if (*p == '\t')
#if 0
col = ((col - 1) & tabmask) + 9;
#else
col += tabsize - (col % tabsize) + 1;
#endif
else
break;
p++;
}
if (col > ps.ind_size)
ps.ind_level = ps.i_l_follow = col / ps.ind_size;
}
/* clean up procedure */
void cleanup(ret)
int ret;
{
if (output != NULL) {
fflush(output);
fclose(output);
}
if (input != NULL) {
fclose(input);
}
#ifdef BUFFERING
if (inbuf != NULL) {
free(inbuf);
}
if (outbuf != NULL) {
free(outbuf);
}
#endif
exit(ret);
}
/* copy input file to backup file. If in_name is /blah/blah/blah/file.foo,
* then backup file will be "file.BAK". Then make the backup file the input
* and original input file the output. */
void bakcopy()
{
int n;
FILE *bakchn;
char extsave[16]; /* MS DOS extension */
register char *p;
char *r;
while ((p = strchr(in_name, '\\')) != NULL) {
/* copy from `\' to end */
p++;
in_name = p;
}
p = in_name;
/* wack off stuff after `.' */
if ((r = strchr(p, '.')) != NULL) {
strcpy(extsave, (r + 1));
*r = NIL; /* terminate string there */
}
sprintf(bakfile, "%s.BAK", p);
/* restore original in_name */
sprintf(in_name, "%s.%s", in_name, extsave);
/* copy in_name to backup file */
if ((bakchn = fopen(bakfile, "w")) == NULL) {
fprintf(stderr, "indent: can't create backup file \"%s\"\n", bakfile);
exit(1);
}
/* copy input file to backup file */
while ((n = getc(input)) != EOF)
putc(n, bakchn);
if ((n = fclose(bakchn)) == EOF) {
fprintf(stderr, "indent: error closeing backup file\n");
exit(1);
}
if ((n = fclose(input)) == EOF) {
fprintf(stderr, "indent: error closeing input file\n");
exit(1);
}
/* re-open backup file as the input file */
if ((input = fopen(bakfile, "r")) == NULL) {
fprintf(stderr, "indent: can't re-open backup file\n");
exit(1);
}
/* now the original input file will be the output */
output = fopen(in_name, "w");
if (output == NULL) {
fprintf(stderr, "indent: can't create %s\n", in_name);
unlink(bakfile);
exit(1);
}
}